package com.study.minio.utils;

import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Clock;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

public abstract class HTTPUtils {

	private static Logger log = LoggerFactory.getLogger(HTTPUtils.class);
	private static OkHttpClient httpClient;

	public static String sendPost(String url, String data) {
		log.info(url + ":::send:::" + data);
		RequestBody body = RequestBody.create(null, data);
		Request request = new Request.Builder().url(url).post(body).build();
		try (Response response = httpClient.newCall(request).execute()) {
			if (response.code() == 200) {
				return response.body().string();
			} else {
				log.error(
						String.format("Response failure on http post: url=%s, data=%s, code=%s, message=%s, content:%s",
								url, data, response.code(), response.message(), response.body().string()));
				return null;
			}
		} catch (Exception e) {
			log.error(String.format("Catch exception on http post: url=%s, data=%s", url, data), e);
			return null;
		}
	}

	public static String sendPostUrlencode(String url, String data) {
		log.info(url + ":::send:::" + data);
		RequestBody body = RequestBody.create(null, data);
		Request request = new Request.Builder().url(url).post(body)
				.addHeader("Content-Type", "application/x-www-form-urlencoded").build();
		try (Response response = httpClient.newCall(request).execute()) {
			if (response.code() == 200) {
				return response.body().string();
			} else {
				log.error(
						String.format("Response failure on http post: url=%s, data=%s, code=%s, message=%s, content:%s",
								url, data, response.code(), response.message(), response.body().string()));
				return null;
			}
		} catch (Exception e) {
			log.error(String.format("Catch exception on http post: url=%s, data=%s", url, data), e);
			return null;
		}
	}

	public static String sendGet(String url) {
		Request request = new Request.Builder().url(url).get().build();
		try (Response response = httpClient.newCall(request).execute()) {
			if (response.code() == 200) {
				return response.body().string();
			} else {
				log.error(String.format("Response failure on http get: url=%s, code=%s, message=%s, content:%s", url,
						response.code(), response.message(), response.body().string()));
				return null;
			}
		} catch (Exception e) {
			log.error(String.format("Catch exception on http get: url=%s", url), e);
			return null;
		}
	}

	public static byte[] sendGetReByte(String url) {
		Request request = new Request.Builder().url(url).get().build();
		try (Response response = httpClient.newCall(request).execute()) {
			if (response.code() == 200) {
				return response.body().bytes();
			} else {
				log.error(String.format("Response failure on http get: url=%s, code=%s, message=%s, content:%s", url,
						response.code(), response.message(), response.body().string()));
				return null;
			}
		} catch (Exception e) {
			log.error(String.format("Catch exception on http get: url=%s", url), e);
			return null;
		}
	}

	static {
		try {
			ConnectionPool connectionPool = new ConnectionPool(Runtime.getRuntime().availableProcessors() * 2, 5,
					TimeUnit.MINUTES);
			OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(1, TimeUnit.MINUTES)
					.readTimeout(1, TimeUnit.MINUTES).writeTimeout(1, TimeUnit.MINUTES).connectionPool(connectionPool);
			SSLContext sslContext = SSLContext.getInstance("TLS");
			X509TrustManager trustManager = new X509TrustManager() {

				@Override
				public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				}

				@Override
				public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				}

				@Override
				public X509Certificate[] getAcceptedIssuers() {
					return new X509Certificate[0];
				}
			};
			sslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom());
			SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
			HostnameVerifier hostnameVerifier = new HostnameVerifier() {

				@Override
				public boolean verify(String hostname, SSLSession session) {
					return true;
				}
			};
			httpClient = builder.sslSocketFactory(sslSocketFactory, trustManager).hostnameVerifier(hostnameVerifier)
					.build();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// public static Optional<String> sendPostImgUpload(String sdkUrl, String
	// targetUrl, String host, String authorization,
	// String boryaAuth, Optional<String> bodyContent) {
	// log.info(sdkUrl + ":::sendImgUpload:::" + authorization);
	// Request request;
	// if (bodyContent.isPresent()) {
	// request = new Request.Builder().url(sdkUrl).addHeader("boryaAuth",
	// boryaAuth)
	// .addHeader("Authorization", authorization).addHeader("url",
	// targetUrl).addHeader("host", host)
	// .post(RequestBody.create(null, bodyContent.get())).build();
	// } else {
	// request = new Request.Builder().url(sdkUrl).addHeader("boryaAuth",
	// boryaAuth)
	// .addHeader("Authorization", authorization).addHeader("url",
	// targetUrl).addHeader("host", host)
	// .post(RequestBody.create(null, "")).build();
	// }
	// try (Response response = httpClient.newCall(request).execute()) {
	// if (response.code() == 200) {
	// return Optional.of(response.body().string());
	// } else {
	// log.error(String.format(
	// "Response failure on http post: sdkAuthUrl=%s,targetUrl=%s,host=%s,
	// authorization=%s, code=%s, message=%s, content:%s",
	// sdkUrl, targetUrl, host, authorization, response.code(),
	// response.message(),
	// response.body().string()));
	// return Optional.empty();
	// }
	// } catch (Exception e) {
	// log.error(
	// String.format("Catch exception on http post:
	// sdkAuthUrl=%s,targetUrl=%s,host=%s, authorization=%s",
	// sdkUrl, targetUrl, host, authorization),
	// e);
	// return Optional.empty();
	// }
	// }

	public static Optional<String> sendPost(String url, Optional<String> bodyContent, Map<String, String> headers) {
		log.info("send :" + url);
		Request.Builder builder = new Request.Builder().url(url);
		if (Objects.nonNull(headers)) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				builder.addHeader(entry.getKey(), entry.getValue());
			}
		}

		Request request;
		if (bodyContent.isPresent()) {
			if (bodyContent.get().length() > 0) {
				request = builder.post(RequestBody.create(null, bodyContent.get())).build();
			} else {
				request = builder.post(RequestBody.create(null, "")).build();
			}
		} else {
			log.info("图片流上传，headers:" + headers);
			request = builder.post(RequestBody.create(null, "")).build();
		}

		try (Response response = httpClient.newCall(request).execute()) {
			if (response.code() == 200) {
				return Optional.of(response.body().string());
			} else {
				log.error(String.format(
						"Response failure on http post: Url=%s,headers=%s, code=%s, message=%s, content:%s", url,
						headers, response.code(), response.message(), response.body().string()));
				return Optional.of(response.message());
			}
		} catch (Exception e) {
			log.error(String.format("Catch exception on http post: sdkAuthUrl=%s,headers=%s", url, headers), e);
			return Optional.empty();
		}
	}

	/**
	 * AliOSSUtil.generatePresignedUrl(url)
	 * @param url
	 * @return
	 */
	public static String sendGetBase64Str(String url) {
		try {
			byte[] bytes = HTTPUtils.sendGetReByte(url);
			if (Objects.isNull(bytes) || bytes.length == 0) {
				return null;
			}
			return new String(Base64.getEncoder().encode(bytes));
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return null;
		}
	}

	public static String sendPostJSON(String url, String data) {
		RequestBody body = RequestBody.create(null, data);
		Request request = new Request.Builder().url(url).post(body)
				.addHeader("Content-Type", "application/json;charset=utf-8").build();
		final long timeStart = Clock.systemDefaultZone().millis();
		try (Response response = httpClient.newCall(request).execute()) {
			if (response.code() == 200) {
				return response.body().string();
			} else {
				log.error(
						String.format("Response failure on http post: url=%s, data=%s, code=%s, message=%s, content:%s",
								url, data, response.code(), response.message(), response.body().string()));
				return null;
			}
		} catch (Exception e) {
			log.error(String.format("Catch exception on http post: url=%s, data=%s", url, data), e);
			return null;
		} finally {
			final long timeEnd = Clock.systemDefaultZone().millis();
//			if (timeEnd - timeStart > Constant.LOG_TIME) {
				log.warn("请求时间过长,耗时" + (timeEnd - timeStart) + "ms,url:" + url);
//			}
		}
	}
}
